﻿using Blazor.CoffeeTalesApi;

namespace Blazor.Services.Device;

public class DeviceService: IDeviceService
{
    private readonly ApiClient _client;

    private readonly Dictionary<Guid, string> _cache = new();
    private bool _pulled = false;

    public DeviceService(AppSetting.AppSetting appSetting, ILogger<DeviceService> logger)
    {
        _client = new ApiClient(logger, appSetting.MainlandApiBaseUri, appSetting.OverseasApiBaseUri);
    }

    public async Task AddOrUpdate(Guid id, string desc)
    {
        await EnsurePulled();

        if (await _client.AddDevice(id, desc))
        {
            _cache.TryAdd(id, desc);
        }
    }

    public async Task Delete(Guid id)
    {
        await EnsurePulled();

        if (await _client.RemoveDevice(id))
        {
            _cache.Remove(id);
        }
    }

    public async ValueTask<IEnumerable<Device>> GetAll()
    {
        await EnsurePulled();

        return _cache.Select(p => new Device
        {
            Id = p.Key,
            Description = p.Value,
        });
    }

    public async ValueTask<string?> GetDescription(Guid id)
    {
        await EnsurePulled();

        _cache.TryGetValue(id, out var desc);
        return desc;
    }

    public async ValueTask<Guid?> GetId(string description)
    {
        foreach (var (name, entry) in _cache)
        {
            if (entry == description)
            {
                return name;
            }
        }

        return null;
    }

    private async ValueTask EnsurePulled(bool isForce = false)
    {
        if (!isForce)
        {
            if (_pulled)
            {
                return;
            }
        }

        var devices = await _client.FetchAllDevicesAsync();
        if (devices is null)
        {
            throw new InvalidOperationException("Failed to fetch devices");
        }

        _cache.Clear();
        foreach (var device in devices)
        {
            _cache.Add(device.Id, device.Description);
        }
        _pulled = true;
    }
}